from typing import List

from redis import Redis

from .nodes.mcp import MCPNodes
from ..graph.base import BaseGraph
from ..graph.nodes import *
from ..llms import LLMConfig, InsCodeModel
from ..mcps import MCPClientManager
from ..models.graph import GraphRequest
from ..parser.xml_parser import XmlToolResultParser
from ..config.agents import LLMType
from loguru import logger


class CoderGraph(BaseGraph):
    """
    专业的软件工程师AI助手，专注于所有编程和开发相关任务。
    应用场景：代码编写、调试、重构、文件操作、命令执行、项目管理、图片分析、网页生成等所有与软件开发相关的工作。
    职责范围：
    - 编程语言：掌握各种主流编程语言、框架和库的使用
    - 代码分析：审查、优化和解释代码
    - 功能开发：实现新功能、API接口和模块设计
    - Bug修复：诊断问题、定位错误并提供解决方案
    - 代码重构：优化代码结构、提高性能和可维护性
    - 应用开发：协助Web、移动和桌面应用程序的开发
    - 文件操作：读取、创建、修改和管理文件
    - 命令执行：运行各类开发相关的命令行指令
    - 信息检索：搜索编程文档、API参考和技术资料
    - 项目辅助：协助设计架构、编写测试、部署和维护
    - 图片问答：分析和解释各种图片内容，包括技术图表、代码截图、UI设计稿等
    - 网页生成：基于图片设计稿或描述生成完整的HTML/CSS/JavaScript网页代码
    - 视觉分析：理解界面设计、架构图、流程图等视觉内容并提供技术实现方案

    系统会根据用户输入的问题自动分析并设置以下参数：
    - title (必选): 基于用户问题生成的标题，能概括问题的核心内容或意图，控制在20个字以内。
        - 对于日常问候类的对话，也需要生成一个合适的标题，如"编程助手初始交流"
        - 标题应该清晰反映用户的意图或需求，便于后续追踪和管理
        - 标题生成是必需的，不可省略
    """
    llm_vl: InsCodeModel = None
    llm_image: InsCodeModel = None

    def __init__(self,
                 llm_vl: InsCodeModel | LLMConfig = None,
                 llm_image: InsCodeModel | LLMConfig = None,
                 redis: Redis = None,
                 nodes: List[BaseNodes] = [],
                 graph_name="agent_coder_",
                 agent_template: str = "agent_coder",
                 mcp_client: MCPClientManager = None,
                 **kwargs):
        super().__init__(graph_name=graph_name,
                         agent_template=agent_template,
                         redis=redis,
                         mcp_client=mcp_client,
                         **kwargs)
        nodes = nodes if nodes else []

        self.llm_vl = InsCodeModel.build(llm_vl if llm_vl else LLMConfig.build_from_type(LLMType.LLM_VL))
        self.llm_image = InsCodeModel.build(llm_image if llm_image else LLMConfig.build_from_type(LLMType.LLM_IMAGE))

        self.nodes = nodes if nodes else [AskUserNodes(), CommandNodes(), CompletionNodes(), FileNodes(), WebNodes(),
                                          ImageNodes(llm_vl=self.llm_vl, llm_image=self.llm_image)]
        if mcp_client:
            self.nodes.append(MCPNodes(mcp_client).use_mcp_tool)
        self.parser = XmlToolResultParser(tools=self.get_nodes_schema())

    async def get_system_template(self, request: GraphRequest, state=None, template_type: str = None):
        """
        Override base implementation to add coder-specific default values.
        """
        if "custom_instructions" not in request.kwargs:
            request.kwargs["custom_instructions"] = ""

        return await super().get_system_template(request=request, state=state, template_type=template_type)

    async def destroy(self):
        """
        Clean up coder-specific resources and call parent cleanup.
        """
        try:

            # Clean up vision LLM client
            if self.llm_vl:
                await self.llm_vl.close()
                self.llm_vl = None

            if self.llm_image:
                await self.llm_image.close()
                self.llm_image = None

            await super().destroy()
        except Exception as e:
            logger.error(f"Error during coder graph cleanup: {e}")
